package galaxy_provide

import (
	"context"
	"sync"
	"time"

	"gddgame.cc/galaxy"
	"gddgame.cc/galaxy/asteroid"
	"gddgame.cc/galaxy/asteroid/adapt/redis"
	"gddgame.cc/galaxy/binocle"
	"gddgame.cc/galaxy/common/bootstrap"
	"gddgame.cc/galaxy/server/composer"
	"gddgame.cc/galaxy/utils/def"
)

type agentTarget struct {
	Agent binocle.Agent `galaxy:"inject"`

	composer.Composer `inject:""`

	Logger def.Logger      `inject:""`
	Config *galaxy.Config  `inject:""`
	Boot   *bootstrap.Boot `inject:""`
}

var (
	adapts = sync.Map{}
)

func AgentProvide() galaxy.ServerProvider {
	t := &agentTarget{}
	return galaxy.ServerProvider{
		Name:   "binocle_agent",
		Inject: t,
		OnCreate: func() error {

			namespace := ""
			if v := t.Config.Read("namespace"); v != nil {
				namespace = v.(string)
			} else {
				namespace = binocle.DefaultNamespace
			}

			group := ""
			if v := t.Config.Read("group"); v != nil {
				group = v.(string)
			} else {
				group = binocle.DefaultGroup
			}

			agent := binocle.NewAgent(t.Logger, namespace, group, func(prefix string) asteroid.Adapt {
				if adapt, ok := adapts.Load(prefix); ok {
					return adapt.(asteroid.Adapt)
				} else {
					adapt := redis.NewAdapt(t.Boot.Redis(), time.Second*15, prefix)
					adapts.Store(prefix, adapt)
					return adapt
				}
			})
			t.Agent = agent
			return nil
		},
		OnStart: func(ctx context.Context) error {
			if err := t.Agent.Start(); err != nil {
				return err
			}
			t.Agent.Cluster().AttachContext(ctx)

			return nil
		},
		OnStop: func() error {
			return t.Agent.Close()
		},
	}
}
